"""
SNV (标准正态变量变换) 处理器

SNV用于消除光程和散射对光谱的影响，是光谱预处理的常用方法。
对每个样本的光谱进行标准化：(x - mean) / std
"""

import pandas as pd
import numpy as np
from ..base import PreprocessorInterface
from ..validation import validate_input_data, safe_copy_dataframe


class SNV(PreprocessorInterface):
    """
    标准正态变量变换 (Standard Normal Variate)
    
    消除光程和散射对光谱的影响。
    对每个样本的光谱进行标准化处理。
    """
    
    def process(self, data: pd.DataFrame) -> pd.DataFrame:
        """
        对光谱数据进行SNV变换
        
        Args:
            data (pd.DataFrame): 输入光谱数据
            
        Returns:
            pd.DataFrame: SNV变换后的数据
        """
        # 验证输入数据
        validate_input_data(data)
        
        # 创建数据副本
        result = safe_copy_dataframe(data)
        
        # 获取光谱数据列（跳过第一列ID列）
        spectral_columns = result.columns[1:]
        spectral_data = result[spectral_columns].values
        
        # 对每个样本进行SNV变换
        snv_spectra = np.zeros_like(spectral_data)
        
        for i in range(spectral_data.shape[0]):
            spectrum = spectral_data[i, :]
            
            # 计算该样本光谱的均值和标准差
            mean_val = np.mean(spectrum)
            std_val = np.std(spectrum, ddof=1)  # 使用样本标准差
            
            # SNV变换：(x - mean) / std
            if std_val > 1e-10:  # 避免除以0
                snv_spectra[i, :] = (spectrum - mean_val) / std_val
            else:
                # 如果标准差接近0，说明光谱值几乎相同，设为0
                snv_spectra[i, :] = np.zeros_like(spectrum)
        
        # 将变换后的数据放回DataFrame
        result[spectral_columns] = snv_spectra
        
        return result
    
    def get_name(self) -> str:
        """返回处理器名称"""
        return "SNV标准正态变量变换"
    
    def get_id(self) -> int:
        """返回唯一ID"""
        return 5